package com.zmj.framework.authorization.filter;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.servlet.ServletUtil;
import cn.hutool.extra.tokenizer.TokenizerUtil;
import cn.hutool.http.Header;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTUtil;
import com.github.benmanes.caffeine.cache.Cache;
import com.zmj.amc.sdk.AmcClientHolder;
import com.zmj.amc.sdk.entity.User;
import com.zmj.framework.exception.client.UnauthorizedException;
import com.zmj.framework.handler.exception.ExceptionMapperUtil;
import com.zmj.framework.response.ResponseCode;
import com.zmj.framework.response.Result;
import com.zmj.framework.util.ThreadContextHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.AsyncHandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;

@Slf4j
public class UserAuthRestInterceptor implements AsyncHandlerInterceptor {

    private AuthorizationConfig authorizationConfig;

    @Autowired
    private Cache<String, Object> caffeineCache;

    public UserAuthRestInterceptor(AuthorizationConfig authorizationConfig) {
        this.authorizationConfig = authorizationConfig;
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        if(! authorizationConfig.isEnable()) {
            return true;
        }
        log.info("请求路径：" + request.getServletPath());
        String authorization = ServletUtil.getHeader(request, Header.AUTHORIZATION.toString(), "utf-8");
        if (StrUtil.isBlank(authorization)) {
            UnauthorizedException unauthorizedException = new UnauthorizedException("未找到token信息");
            fail(response, ExceptionMapperUtil.buildBody(unauthorizedException, ResponseCode.UNAUTHORIZED));
            return false;
        }
        String token = StrUtil.subAfter(authorization, "Bearer ", true);
        try {
            List<String> jwt = StrUtil.split(token, ".");
            if(CollectionUtil.size(jwt) < 3) {
                UnauthorizedException unauthorizedException = new UnauthorizedException("token格式异常");
                fail(response, ExceptionMapperUtil.buildBody(unauthorizedException, ResponseCode.UNAUTHORIZED));
                return false;
            }
            JSONObject userOfJwtJson = JWT.of(token).getPayloads();
            User user = new User();
            Object cacheObject = caffeineCache.asMap().get(token);
            if (ObjectUtil.isNotNull(cacheObject) ) {
                user = (User) cacheObject;
            } else {
                if (StrUtil.equals(userOfJwtJson.getStr("sub"), userOfJwtJson.getStr("aud"))) {
                    //客户端模式
                    user.setDescription("client:"+userOfJwtJson.getStr("sub"));
                } else {
                    user = AmcClientHolder.getUserByToken(token);
                }
                caffeineCache.put(token,user);
            }
            ThreadContextHandler.setToken(authorization);
            ThreadContextHandler.setCurrentUser(user);
            return true;
        } catch (Exception e) {
            log.error(e.getMessage());
            UnauthorizedException unauthorizedException = new UnauthorizedException("token认证失败");
            fail( response,ExceptionMapperUtil.buildBody(unauthorizedException, ResponseCode.UNAUTHORIZED));
            return false;
        }

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        ThreadContextHandler.remove();
    }

    private void fail(HttpServletResponse response, Result resultBody) {
        try {
            //response.setContentType("text/html;charset=UTF-8");
            response.setContentType("application/json;charset=UTF-8");
            response.setStatus(resultBody.getCode());
            PrintWriter out = response.getWriter();
            out.print(JSONUtil.toJsonStr(resultBody));
            out.flush();
            out.close();
        } catch (IOException e) {
            log.error("UserAuthRestInterceptor异常：",resultBody.toString(),e);
        }
    }

}
